﻿#region Using Directives

    using System;
    using System.Collections.Generic;
    using System.Linq;

    using Csla;

#endregion

namespace MarketPulse.Reporting.Core
{
    /// <summary>
    /// The relationship between this value and previous values.
    /// Really just UI hints
    /// </summary>
    [Serializable]
    public enum MeasureStatus
    {
        /// <summary>
        /// No relationship to other values
        /// </summary>
        None,

        /// <summary>
        /// Exceeded some threshold
        /// </summary>
        Exceeded,
        
        /// <summary>
        /// Some threshold no met
        /// </summary>
        NotMet,
        
        /// <summary>
        /// Some threshold met
        /// </summary>
        Met,

        /// <summary>
        /// Up from some previous value
        /// </summary>
        Up,

        /// <summary>
        /// Down from some previous value
        /// </summary>
        Down,

        /// <summary>
        /// Unchanged from some previous value
        /// </summary>
        Unchanged
    };

    /// <summary>
    /// This is a container class to add some functionality to the Measures class.
    /// </summary>
    /// <typeparam name="T">The StorageType used.</typeparam>
    [Serializable]
    public class MeasureCollection<T> : List<Measure<T>> where T : struct
    {
        /// <summary>
        /// Get a Measure by the DisplayName property.
        /// </summary>
        /// <param name="displayName">The DisplayName of the measure to retrieve.</param>
        /// <returns>A measure.</returns>
        public Measure<T> this[string displayName]
        {
            get
            {
                return GetByDisplayName(displayName);
            }
        }

        /// <summary>
        /// Gert a MeasureCollection containing measures with the given Name.
        /// </summary>
        /// <param name="name">The Name to search the MeasuresCollection for.</param>
        /// <returns>A collection of Measures with the given name.</returns>
        public MeasureCollection<T> GetByName(string name)
        {
            var measures = new MeasureCollection<T>();
            this.ForEach(delegate(Measure<T> measure)
            {
                if (measure.Name.Equals(name))
                {
                    measures.Add(measure);
                }
            });
            return measures;
        }

        /// <summary>
        /// Get a Measure by the DisplayName property.
        /// </summary>
        /// <param name="displayName">The DisplayName of the measure to retrieve.</param>
        /// <returns>A measure.</returns>
        public Measure<T> GetByDisplayName(string displayName)
        {
            return this.Where(m => m.DisplayName.Equals(displayName)).FirstOrDefault();
        }
    }

    /// <summary>
    /// This class represents a read only instance of a Measure within the system.
    /// This class is not a fully-fledged Csla business object.  It is structural
    /// and not intended to have any significant behaviors.  
    /// </summary>
    [Serializable]
    public class Measure<StorageType> where StorageType : struct
    {

        #region Constructors

            /// <summary>
            /// Default constructor.  The constructor has
            /// access specifier of internal to prevent explicit construction outside
            /// of this assembly.
            /// </summary>
            public Measure(string name,
                            string displayName,
                            StorageType value,
                            StorageType min,
                            StorageType max,
                            Dictionary<string, double> statistics,
                            MeasureStatus status)
            {
                mName = name;
                mDisplayName = displayName;
                mValue = value;
                mMinValue = min;
                mMaxValue = max;
                mStatistics = statistics;
                mMeasureStatus = status;
            }

        #endregion    

        #region Properties

            /// <summary>
            /// The name of this measure
            /// </summary>
            protected string mName;
            public string Name {
                get { return mName; }
            }

            /// <summary>
            /// The displayed name of this measure
            /// </summary>
            protected string mDisplayName;
            public string DisplayName
            {
                get { return mDisplayName; }
            }

            /// <summary>
            /// The value of this measure
            /// </summary>
            protected StorageType mValue;
            public StorageType Value
            {
                get { return mValue; }
            }

            /// <summary>
            /// A collection of statistical measures of this measure
            /// </summary>
            protected Dictionary<string, double> mStatistics;
            public Dictionary<string, double> Statistics
            {
                get { return mStatistics; }
            }

            /// <summary>
            /// The maximum value this measure can take.  Hint to a UI control.
            /// </summary>
            protected StorageType mMaxValue;
            public StorageType MaxValue
            {
                get { return mMaxValue; }
            }

            /// <summary>
            /// The minimum value this measure can take.  Hint to a UI control.
            /// </summary>
            protected StorageType mMinValue;
            public StorageType MinValue
            {
                get { return mMinValue; }
            }

            /// <summary>
            /// The relationship between this value and previous values.
            /// </summary>
            protected MeasureStatus mMeasureStatus;
            public MeasureStatus MeasureStatus
            {
                get { return mMeasureStatus; }
            }

        #endregion
    }
}
